home *** CD-ROM | disk | FTP | other *** search
- // The color_selector class implementation
- #include <mem.h>
- #include <alloc.h>
- #include "common.h"
- #include "graph.h"
- #include "palette.h"
-
- void color_selector::prescan_line (BYTE *R, BYTE *G, BYTE *B) {
-
- BYTE *ptr0, *ptr1, *ptr2; //I do know, how many registers are
- register histptr histp; //are in PC, but...
- register int c0, c1, c2;
- int col; //col-umn, not color!
- ptr0 = R;
- ptr1 = G;
- ptr2 = B;
- for (col = width; col > 0; col--) {
- /* get pixel value and index into the histogram */
- c0 = (*ptr0++) >> R_SHIFT;
- c1 = (*ptr1++) >> G_SHIFT;
- c2 = (*ptr2++) >> B_SHIFT;
- histp = & histogram[c0][c1][c2];
- /* increment, check for overflow and undo increment if so. */
- /* We assume unsigned representation here! */
- if (++(*histp) == 0) (*histp)--;
- }
- }
-
- void color_selector::prepare_scan_palette (BGRpalette pal) {
- int i;
- for (i = 0; i < 256; i++) {
- my_colormap[i].r = pal[i].r >> R_SHIFT;
- my_colormap[i].g = pal[i].g >> G_SHIFT;
- my_colormap[i].b = pal[i].b >> B_SHIFT;
- }
- }
-
- void color_selector::prescan_line_palette (BYTE *source) {
- register histptr histp;
- register int c0, c1, c2;
- BGRcolortype color;
- int col; //col-umn, not color!
- for (col = width; col > 0; col--) {
- /* get pixel value and index into the histogram */
- color = my_colormap[*(source++)];
- c0 = color.r;
- c1 = color.g;
- c2 = color.b;
- histp = & histogram[c0][c1][c2];
- /* increment, check for overflow and undo increment if so. */
- /* We assume unsigned representation here! */
- if (++(*histp) == 0) (*histp)--;
- }
- }
-
-
- /*
- * Now we have the really interesting routines: selection of a colorhist
- * given the completed histogram.
- * These routines work with a list of "boxes", each representing a rectangular
- * subset of the input color space (to histogram precision).
- */
-
- boxptr color_selector::find_biggest_color_pop() {
- /* Find the splittable box with the largest color population */
- /* Returns NULL if no splittable boxes remain */
-
- register boxptr boxp;
- register int i;
- register long maxc = 0;
- boxptr which = NULL;
-
- for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
- if (boxp->colorcount > maxc) {
- if (boxp->splitable) {
- which = boxp;
- maxc = boxp->colorcount;
- }
- }
- }
- return which;
- }
-
- boxptr color_selector:: find_biggest_volume () {
- /* Find the splittable box with the largest (scaled) volume */
- /* Returns NULL if no splittable boxes remain */
-
- register boxptr boxp;
- register int i;
- register long maxv = 0;
- register long norm, c0,c1,c2;
- boxptr which = NULL;
-
- /* We use 2-norm rather than real volume here.
- * Some care is needed since the differences are expressed in
- * histogram-cell units; if HIST_Y_BITS != HIST_C_BITS, we have to
- * adjust the scaling to get the proper scaled-YCbCr-space distance.
- * This code won't work right if HIST_Y_BITS < HIST_C_BITS,
- * but that shouldn't ever be true.
- * Note norm > 0 iff box is splittable, so need not check separately.
- * original volume calculation
- * c0 = (boxp->c0max - boxp->c0min) * Y_SCALE;
- * c1 = (boxp->c1max - boxp->c1min) << (HIST_Y_BITS-HIST_C_BITS);
- * c2 = (boxp->c2max - boxp->c2min) << (HIST_Y_BITS-HIST_C_BITS);
- * norm = c0*c0 + c1*c1 + c2*c2;
- * Alas, it's not right for my volume - E.P., see update_box
- */
-
- for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
- norm = boxp->volume;
- if ((boxp->splitable) && (norm > maxv)) {
- which = boxp;
- maxv = norm;
- }
- }
- return which;
- }
-
- void color_selector::update_box (boxptr boxp) {
- /* Shrink the min/max bounds of a box to enclose only nonzero elements, */
- /* and recompute its population */
- histptr histp;
- int c0,c1,c2;
- int c0min,c0max,c1min,c1max,c2min,c2max;
- unsigned long ccount;
-
- c0min = boxp->c0min; c0max = boxp->c0max;
- c1min = boxp->c1min; c1max = boxp->c1max;
- c2min = boxp->c2min; c2max = boxp->c2max;
- if (c0max > c0min)
- for (c0 = c0min; c0 <= c0max; c0++)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c0min = c0min = c0;
- goto have_c0min;
- }
- }
- have_c0min:
- if (c0max > c0min)
- for (c0 = c0max; c0 >= c0min; c0--)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c0max = c0max = c0;
- goto have_c0max;
- }
- }
- have_c0max:
- if (c1max > c1min)
- for (c1 = c1min; c1 <= c1max; c1++)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c1min = c1min = c1;
- goto have_c1min;
- }
- }
- have_c1min:
- if (c1max > c1min)
- for (c1 = c1max; c1 >= c1min; c1--)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++)
- if (*histp++ != 0) {
- boxp->c1max = c1max = c1;
- goto have_c1max;
- }
- }
- have_c1max:
- if (c2max > c2min)
- for (c2 = c2min; c2 <= c2max; c2++)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1min][c2];
- for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_B_ELEMS)
- if (*histp != 0) {
- boxp->c2min = c2min = c2;
- goto have_c2min;
- }
- }
- have_c2min:
- if (c2max > c2min)
- for (c2 = c2max; c2 >= c2min; c2--)
- for (c0 = c0min; c0 <= c0max; c0++) {
- histp = & histogram[c0][c1min][c2];
- for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_B_ELEMS)
- if (*histp != 0) {
- boxp->c2max = c2max = c2;
- goto have_c2max;
- }
- }
- have_c2max:
-
- /* Now scan remaining volume of box and compute population */
- ccount = 0;
- for (c0 = c0min; c0 <= c0max; c0++)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++, histp++)
- // if (*histp != 0) ccount ++;
- ccount += *histp;
- }
- boxp->colorcount = ccount;
- boxp->splitable = (c0max > c0min || c1max > c1min || c2max > c2min);
-
- // this was added by E.P.
- // assumed HIST_G_BITS >= HIST_R_BITS >= HIST_B_BITS !!!
-
- c0 = ((c0max - c0min + 1) << (HIST_G_BITS-HIST_R_BITS)) * RSCALE >> 4;
- c1 = (c1max - c1min + 1) * GSCALE >> 4;
- c2 = (c2max - c2min + 1) << (HIST_G_BITS-HIST_B_BITS);
- boxp->volume = c0*c0 + c1*c1 + c2*c2;
- }
-
-
- void color_selector:: median_cut () {
- /* Repeatedly select and split the largest box until we have enough boxes */
-
- int n,lb;
- int c0,c1,c2,cmax;
- register boxptr b1,b2;
-
- while (numboxes < desired_colors) {
- /* Select box to split */
- /* Current algorithm: by population for first half, then by volume */
- if (numboxes*2 <= desired_colors) {
- b1 = find_biggest_color_pop();
- } else {
- b1 = find_biggest_volume();
- }
- // if (numboxes >= 131) lb = numboxes;
-
- if (b1 == NULL) /* no splittable boxes left! */
- break;
- b2 = &boxlist[numboxes]; /* where new box will go */
- /* Copy the color bounds to the new box. */
-
- b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max;
- b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min;
-
- /* Choose which axis to split the box on.
- * Current algorithm: longest scaled axis.
- * See notes in find_biggest_volume about scaling...
- */
-
- // and selected axe is to be splittable!!! - E.P.
-
- if ((c0 = b1->c0max - b1->c0min) > 0)
- c0 = ((c0+1) << (HIST_G_BITS-HIST_R_BITS)) * RSCALE >> 4;
- if ((c1 = b1->c1max - b1->c1min) > 0)
- c1 = (c1+1) * GSCALE >> 4;
- if ((c2 = b1->c2max - b1->c2min) > 0)
- c2 = (c2 + 1) << (HIST_G_BITS-HIST_B_BITS);
- cmax = c0; n = 0;
- if (c1 > cmax) { cmax = c1; n = 1; }
- if (c2 > cmax) { n = 2; }
- /* Choose split point along selected axis, and update box bounds.
- * Current algorithm: split at halfway point.
- * (Since the box has been shrunk to minimum volume,
- * any split will produce two nonempty subboxes.)
- * Note that lb value is max for lower box, so must be < old max.
- */
-
- switch (n) {
- case 0:
- lb = (b1->c0max + b1->c0min) / 2;
- b1->c0max = lb;
- b2->c0min = lb+1;
- break;
- case 1:
- lb = (b1->c1max + b1->c1min) / 2;
- b1->c1max = lb;
- b2->c1min = lb+1;
- break;
- case 2:
- lb = (b1->c2max + b1->c2min) / 2;
- b1->c2max = lb;
- b2->c2min = lb+1;
- break;
- }
- /* Update stats for boxes */
- update_box(b1);
- update_box(b2);
- numboxes++;
- }
- }
-
-
- void color_selector:: compute_color (boxptr boxp, BGRcolortype &color) {
-
- /* Compute representative color for a box, put it in my_colorhist[icolor] */
- /* Current algorithm: mean weighted by pixels (not colors) */
- /* Note it is important to get the rounding correct! */
- histptr histp;
- int c0,c1,c2;
- int c0min,c0max,c1min,c1max,c2min,c2max;
- long count;
- long total = 0;
- long c0total = 0;
- long c1total = 0;
- long c2total = 0;
-
- c0min = boxp->c0min; c0max = boxp->c0max;
- c1min = boxp->c1min; c1max = boxp->c1max;
- c2min = boxp->c2min; c2max = boxp->c2max;
-
- for (c0 = c0min; c0 <= c0max; c0++)
- for (c1 = c1min; c1 <= c1max; c1++) {
- histp = & histogram[c0][c1][c2min];
- for (c2 = c2min; c2 <= c2max; c2++) {
- if ((count = *histp++) != 0) {
- total += count;
- c0total += ((c0 << R_SHIFT) + ((1<<R_SHIFT)>>1)) * count;
- c1total += ((c1 << G_SHIFT) + ((1<<G_SHIFT)>>1)) * count;
- c2total += ((c2 << B_SHIFT) + ((1<<B_SHIFT)>>1)) * count;
- }
- }
- }
-
- // - Naturally, it was brutally rewritten by E.P.
- color.r = (BYTE) ((c0total + (total>>1)) / total);
- color.g = (BYTE) ((c1total + (total>>1)) / total);
- color.b = (BYTE) ((c2total + (total>>1)) / total);
- }
-
-
- void color_selector:: select_colors () {
- /* Master routine for color selection */
- int i,j;
-
- /* Allocate workspace for box list */
- // boxlist = (boxptr) (*cinfo->emethods->alloc_small) (desired * SIZEOF(box));
- boxlist = new box[desired_colors];
- /* Initialize one box containing whole space */
- numboxes = 1;
- boxlist[0].c0min = 0;
- boxlist[0].c0max = (1 << HIST_R_BITS )- 1;
- boxlist[0].c1min = 0;
- boxlist[0].c1max = (1 << HIST_G_BITS) - 1;
- boxlist[0].c2min = 0;
- boxlist[0].c2max = (1 << HIST_B_BITS) - 1;
- /* Shrink it to actually-used volume and set its statistics */
- update_box(& boxlist[0]);
- /* Perform median-cut to produce final box list */
- median_cut();
- /* Compute the representative color for each box, fill my_colorhist[] */
- for (i = 0; i < numboxes; i++) {
- compute_color(& boxlist[i], my_colormap[i]);
- }
- actual_number_of_colors = numboxes;
- delete boxlist;
- }
-
- /*
- * Initialize for two-pass color quantization.
- */
-
- color_selector::color_selector(int desired_colors_,int width_){
- int i;
-
- initialized = FALSE;
- desired_colors = desired_colors_;
- width = width_;
- /* Lower bound on # of colors ... somewhat arbitrary as long as > 0 */
- if (desired_colors_ < 8) return;
- if (desired_colors_ > MAXNUMCOLORS) return;
-
- /* Allocate and zero the hist */
-
- /* I killed thoroughly distingued types of memory allocation - E.P.*/
- histogram = new hist2d[HIST_R_ELEMS];
- for (i = 0; i < HIST_R_ELEMS; i++) histogram[i] = NULL;
-
-
- for (i = 0; i < HIST_R_ELEMS; i++) {
- histogram[i] = (hist2d) new histcell[HIST_G_ELEMS][HIST_B_ELEMS];
- if (histogram[i] == NULL) return;
- memset(histogram[i],0,HIST_G_ELEMS*HIST_B_ELEMS * sizeof(histcell));
- }
-
- initialized = TRUE;
- }
-
- color_selector::~color_selector() {
- int i;
- for (i = 0; i < HIST_R_ELEMS; i++) if (histogram[i] != NULL) delete histogram[i];
- delete histogram;
- }
-
-
-